package com.foreverwin.jzymes.production.gr.service.impl;

import com.foreverwin.jzymes.common.constant.Constants;
import com.foreverwin.jzymes.common.service.*;
import com.foreverwin.jzymes.common.util.BOHandleUtil;
import com.foreverwin.jzymes.common.util.CommonMethods;
import com.foreverwin.jzymes.framework.exception.BusinessException;
import com.foreverwin.jzymes.framework.util.DateUtil;
import com.foreverwin.jzymes.framework.util.I18nUtil;
import com.foreverwin.jzymes.framework.util.SapUtil;
import com.foreverwin.jzymes.production.gr.domain.GoodsReceiptLog;
import com.foreverwin.jzymes.production.gr.enums.GoodsReceiptStatusEnum;
import com.foreverwin.jzymes.production.gr.enums.GoodsReceiveTypeEnum;
import com.foreverwin.jzymes.production.gr.service.IGoodsReceiptLogAdviceService;
import com.foreverwin.jzymes.production.gr.service.IGoodsReceiptLogService;
import com.foreverwin.jzymes.production.sfc.domain.SFC;
import com.foreverwin.jzymes.production.sfc.service.ISFCService;
import com.sap.conn.jco.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.*;

@Service
public class GoodsReceiptLogAdviceServiceImpl implements IGoodsReceiptLogAdviceService {

    @Autowired
    ISiteAdviceService siteAdviceService;
    @Autowired
    IItemAdviceService itemAdviceService;
    @Autowired
    IItemGroupAdviceService itemGroupAdviceService;
    @Autowired
    ISFCService sfcService;
    @Autowired
    ICustomFieldsAdviceService customFieldsAdviceService;
    @Autowired
    IGoodsReceiptLogService goodsReceiptLogService;
    @Autowired
    ISystemRuleAdviceService systemRuleAdviceService;
    @Autowired
    ICommonService commonService;

    @Value("${mes.sap.activeDestination}")
    private String destination;

    private ThreadLocal<String> itemType = new InheritableThreadLocal<>();

    /**
     * 成品入库
     *
     * @param goodsReceiptLogs
     */
    @Transactional( propagation = Propagation.REQUIRED, rollbackFor = Exception.class )
    public Map<String,String> goodsReceive( List<GoodsReceiptLog> goodsReceiptLogs ){

        initFields();

        /**检查入库明细*/
        Assert.notEmpty( goodsReceiptLogs, I18nUtil.getI18nText( "production.gr.goodsReceiptListNotEmpty" ) );

        /**更新工令表*/
        updateSfc( goodsReceiptLogs );

        /**入库明细传入ERP*/
        String orderNo = generateOrderNo();
        //String orderNo = "GR11" +  DateUtil.format( new Date(), "yyMMddHHmm"  );
        //String erpDocNo =  DateUtil.format( new Date(), "yyyyMMddHHmm"  );
        String erpDocNo = null;
        if( "M".equals( itemType.get() ) ){
            erpDocNo = postErpForProduct( goodsReceiptLogs, orderNo );
        }else if( "B".equals( itemType.get() ) ){
            erpDocNo = postErpForSemi( goodsReceiptLogs, orderNo );
        }else if( "P".equals( itemType.get() ) ){
            erpDocNo = postErpForRaw( goodsReceiptLogs, orderNo );
        }else{
            throw BusinessException.build( "production.gr.functionNotSupport", new String[]{ itemType.get() } );
        }

        /**保存入库明细及凭证*/
        for( GoodsReceiptLog goodsReceiptLog : goodsReceiptLogs ){
            goodsReceiptLog.setOrderNo( orderNo );
            goodsReceiptLog.setStatus( GoodsReceiptStatusEnum.Y.name() );
            goodsReceiptLog.setDocumentNo( erpDocNo );
            goodsReceiptLog.setCreateUserBo( CommonMethods.getUserBo() );
            goodsReceiptLog.setHandle( BOHandleUtil.buildGoodsReceiptLogHandle() );
            goodsReceiptLogService.insertGoodsReceiptLog( goodsReceiptLog );
        }

        Map<String,String> rtnMap = new HashMap<>();
        rtnMap.put( "orderNo", orderNo );
        rtnMap.put( "documentNo", erpDocNo );
        return rtnMap;
    }

    public void initFields(){
        itemType.remove();
    }

    /**
     * 更新工令数据
     *
     * @param goodsReceiptLogs
     */
    public void updateSfc( List<GoodsReceiptLog> goodsReceiptLogs ){
        String site = CommonMethods.getSite();
        List<String> sfcList = new ArrayList<>();
        for( GoodsReceiptLog goodsReceiptLog : goodsReceiptLogs ){
            goodsReceiptLog.setSite( site );
            goodsReceiptLog.setMachineType( commonService.findItemGroupByItem( site, goodsReceiptLog.getItemBo() ) );
            goodsReceiptLog.setCreatedDateTime( new Date() );

            /**检查入库明细字段*/
            checkFieldsForReceive( goodsReceiptLog );

            /**ERP不允许不同物料类型一起过账，接口不同*/
            Map<String,Object> itemMap = itemAdviceService.existItem( goodsReceiptLog.getItemBo() );
            if( itemType.get() == null  ){
                itemType.set((String) itemMap.get( "ITEM_TYPE" ));
            //}else if( !itemType.get().equals( itemMap.get( "ITEM_TYPE" ) ) && ( "P".equals( itemType ) || "P".equals( itemMap.get( "ITEM_TYPE" ) ) ) ){
            }else if( !itemType.get().equals( itemMap.get( "ITEM_TYPE" ) ) ){
                throw BusinessException.build( "production.gr.itemTypeNotDiff", new Object[]{ itemMap.get( "ITEM" ), itemMap.get( "ITEM_TYPE" ), itemType.get() } );
            }

            /**检查入库明细工令和库位是否重复*/
            if( sfcList.contains( goodsReceiptLog.getSfc() + "," + goodsReceiptLog.getItemBo() + "," + goodsReceiptLog.getGrType() + "," + goodsReceiptLog.getStorageLocation() ) ){
                throw BusinessException.build("production.gr.sfcGoodsReceiptDuplicate", new String[]{ goodsReceiptLog.getSfc(), goodsReceiptLog.getStorageLocation() } );
            }
            sfcList.add( goodsReceiptLog.getSfc() + "," + goodsReceiptLog.getItemBo() + "," + goodsReceiptLog.getGrType() + "," + goodsReceiptLog.getStorageLocation() );

            /**获取工令*/
            SFC sfc = sfcService.selectSFCById( BOHandleUtil.buildSFCHandle( goodsReceiptLog.getSite(), goodsReceiptLog.getSfc() ) );
            if( sfc == null ){
                throw BusinessException.build( "production.sfc.sfcNotExist", new String[]{ goodsReceiptLog.getSfc() } );
            }

            /**检查入库类型*/
            String grType = goodsReceiptLog.getGrType();
            if( GoodsReceiveTypeEnum.OK_PRODUCT == GoodsReceiveTypeEnum.fromValue( grType ) || GoodsReceiveTypeEnum.OK_SEMI == GoodsReceiveTypeEnum.fromValue( grType ) ){
                sfc.setOkQty( sfc.getOkQty() + goodsReceiptLog.getQty() );
            }
            if( GoodsReceiveTypeEnum.NG_PRODUCT == GoodsReceiveTypeEnum.fromValue( grType ) || GoodsReceiveTypeEnum.NG_SEMI == GoodsReceiveTypeEnum.fromValue( grType ) ){
                sfc.setNgQty( sfc.getNgQty() + goodsReceiptLog.getQty() );
            }
            if( GoodsReceiveTypeEnum.SCRAP_PRODUCT == GoodsReceiveTypeEnum.fromValue( grType ) || GoodsReceiveTypeEnum.SCRAP_SEMI == GoodsReceiveTypeEnum.fromValue( grType ) ){
                sfc.setScrapQty( sfc.getScrapQty() + goodsReceiptLog.getQty() );
            }
            if( GoodsReceiveTypeEnum.NG_RAW == GoodsReceiveTypeEnum.fromValue( grType ) ){
                sfc.setRawNcQty( sfc.getRawNcQty() + goodsReceiptLog.getQty() );
            }
            if( GoodsReceiveTypeEnum.OK_RAW == GoodsReceiveTypeEnum.fromValue( grType ) ){
                sfc.setRawOkQty( sfc.getRawOkQty() + goodsReceiptLog.getQty() );
            }
            if( sfc.getOkQty() + sfc.getNgQty() + sfc.getScrapQty() + sfc.getRawNcQty() + sfc.getRawOkQty() > sfc.getSfcQty() ){
                throw BusinessException.build( "production.gr.goodsReceiptQtyExceedSfcQty", new Object[]{ sfc.getSfc(), sfc.getOkQty(), sfc.getNgQty(), sfc.getScrapQty(), sfc.getRawNcQty(), sfc.getRawOkQty(), sfc.getSfcQty() } );
            }

            if( sfc.getOkQty() + sfc.getNgQty() + sfc.getScrapQty() + sfc.getRawNcQty() + sfc.getRawOkQty() == sfc.getSfcQty() ){
                sfc.setStatusBo( "StatusBO:"+ site +",405" );
                sfc.setActEndTime( goodsReceiptLog.getCreatedDateTime() );
            }
            sfc.setUpdatedDateTime( goodsReceiptLog.getCreatedDateTime() );
            sfc.setUpdateUserBo( CommonMethods.getUserBo() );
            sfcService.updateSFC( sfc );
        }
    }

    /**
     * 生成入库单号
     *
     * @return
     */
    public String generateOrderNo(){
        String site = CommonMethods.getSite();
        String orderNumberRule = systemRuleAdviceService.existSystemRule( site, Constants.SYSTEM_RULE_GOODS_RECEIPT_NUMBER_RULE );
        String orderNo = commonService.generateOrderNo( site, orderNumberRule );
        return orderNo;
    }


    /**
     * 成品入库数据抛送ERP
     *
     * @param goodsReceiptLogs
     * @param orderNo
     * @return
     */
    public String postErpForProduct( List<GoodsReceiptLog> goodsReceiptLogs, String orderNo ){
        String site = CommonMethods.getSite();

        String moveType = systemRuleAdviceService.existSystemRule( site, Constants.SYSTEM_RULE_PRDT_MOVE_TYPE );
        String erpDocNo = postErpForDoc( goodsReceiptLogs, orderNo, "MES成品入库", moveType, "ZMM_GR_CREATE" );
        return erpDocNo;
    }

    /**
     * 半成品入库数据抛送ERP
     *
     * @param goodsReceiptLogs
     * @param orderNo
     * @return
     */
    public String postErpForSemi( List<GoodsReceiptLog> goodsReceiptLogs, String orderNo ){
        String site = CommonMethods.getSite();

        String moveType = systemRuleAdviceService.existSystemRule( site, Constants.SYSTEM_RULE_PRDT_MOVE_TYPE );
        String erpDocNo = postErpForDoc( goodsReceiptLogs, orderNo, "MES半成品入库", moveType, "ZMM_GR_CREATE" );
        return erpDocNo;
    }

    /**
     * 原材料退库数据抛送ERP
     *
     * @param goodsReceiptLogs
     * @param orderNo
     * @return
     */
    public String postErpForRaw( List<GoodsReceiptLog> goodsReceiptLogs, String orderNo ){
        String site = CommonMethods.getSite();

        String moveType = systemRuleAdviceService.existSystemRule( site, Constants.SYSTEM_RULE_RAW_RETURN_MOVE_TYPE );
        String erpDocNo = postErpForDoc( goodsReceiptLogs, orderNo, "MES原材料退库", moveType, "ZMM_RET_CREATE" );
        return erpDocNo;
    }

    /**
     * 数据抛送ERP
     *
     * @param goodsReceiptLogs
     * @param orderNo
     * @param grDesc
     * @param moveType
     * @param rfcName
     * @return
     */
    public String postErpForDoc( List<GoodsReceiptLog> goodsReceiptLogs, String orderNo, String grDesc, String moveType, String rfcName ){
        String site = CommonMethods.getSite();

        //String costCenter = "JZY07002";
        String costCenter = systemRuleAdviceService.existSystemRule( site, Constants.PICKING_RKPF_KOSTL );
        String erpPlant = systemRuleAdviceService.existSystemRule( site, Constants.SYSTEM_RULE_ERP_PLANT );

        String erpDocNo = null;
        String failMessage = null;

        try {
            JCoDestination jcoDestination = SapUtil.getDestination( destination );
            JCoFunction jcoFunction = SapUtil.getFunction( destination, rfcName );

            JCoContext.begin( jcoDestination );

            JCoTable headTable = jcoFunction.getTableParameterList().getTable("ET_HEAD");
            headTable.appendRow();
            headTable.setValue("XABLN", orderNo );
            headTable.setValue("BUDAT", DateUtil.format( goodsReceiptLogs.get( 0 ).getPostDate(), "yyyyMMdd" ) );
            headTable.setValue( "BKTXT", grDesc );
            headTable.setValue( "WERKS", erpPlant );
            headTable.setValue( "BWART", moveType );
            headTable.setValue( "KOSTL", costCenter );
            headTable.setValue( "LGORT", goodsReceiptLogs.get( 0 ).getStorageLocation() );

            JCoTable itemTable = jcoFunction.getTableParameterList().getTable("ET_ITEM");
            int i = 1;
            for( GoodsReceiptLog goodsReceiptLog : goodsReceiptLogs ){
                Map<String,Object> itemMap = itemAdviceService.existItem( goodsReceiptLog.getItemBo() );
                itemTable.appendRow();
                itemTable.setValue( "XABLN", orderNo );
                itemTable.setValue( "ZEILE", i * 10 );
                itemTable.setValue( "MATNR", itemMap.get( "ITEM" ) );
                itemTable.setValue( "MAKTX", itemMap.get( "DESCRIPTION" ) );
                itemTable.setValue( "MENGE", goodsReceiptLog.getQty() );
                itemTable.setValue( "SGTXT", goodsReceiptLog.getSfc() );
                itemTable.setValue( "WEMPF", goodsReceiptLog.getMachineType() );
                itemTable.setValue( "ABLAD", findPickOperation( goodsReceiptLog.getSite(), goodsReceiptLog.getMachineType() ) );
                i++;
            }

            jcoFunction.execute( jcoDestination );

            JCoTable exportTable = jcoFunction.getTableParameterList().getTable("ET_OUT");
            exportTable.setRow(0);
            erpDocNo = exportTable.getString("MBLNR");
            failMessage = exportTable.getString("MSGTX");

            JCoContext.end( jcoDestination );
        } catch (JCoException e) {
            throw BusinessException.build( "production.gr.goodsReceiptFail", new String[]{ e.getMessageText() } );
        }
        if( StringUtils.isBlank( erpDocNo ) ){
            throw BusinessException.build( "production.gr.goodsReceiptFail", new String[]{ failMessage } );
        }
        return erpDocNo;
    }


    /**
     * 检查入库字段
     *
     * @param goodsReceiptLog
     */
    public void checkFieldsForReceive( GoodsReceiptLog goodsReceiptLog ){
        /**检查站点*/
        siteAdviceService.existSite( goodsReceiptLog.getSite() );
        /**检查物料*/
        itemAdviceService.existItem( goodsReceiptLog.getItemBo() );
        /**检查工令*/
        Assert.hasText( goodsReceiptLog.getSfc(), I18nUtil.getI18nText( "common.sfcNotBlank" ) );
        /**检查仓码*/
        Assert.hasText( goodsReceiptLog.getStorageLocation(), I18nUtil.getI18nText( "production.gr.storageLocationNotBlank", new String[]{ BOHandleUtil.splitItemHandle( goodsReceiptLog.getItemBo() )[1] } ) );
        /**检查入库数量*/
        Assert.isTrue( goodsReceiptLog.getQty() != null && goodsReceiptLog.getQty() > 0, I18nUtil.getI18nText( "production.gr.qtyNotValid", new Object[]{ goodsReceiptLog.getQty() } ) );
    }

    public String findPickOperation( String site, String itemGroup ){
        String itemGroupBo = BOHandleUtil.buildItemGroupHandle( site, itemGroup );
        /**对应ERP卸货点(工序)*/
        String pickOperation = customFieldsAdviceService.existCustomValue( itemGroupBo, Constants.ITEM_GROUP_CUSTOM_FIELD_PICK_OPERATION );
        return pickOperation;
    }
}
